<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>物联网设备控制中心</title>
    <!-- 引入外部资源 -->
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>

    <!-- 配置Tailwind自定义颜色 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#165DFF',
                        secondary: '#36CFC9',
                        success: '#00B42A',
                        danger: '#F53F3F',
                        warning: '#FF7D00',
                        info: '#86909C'
                    }
                }
            }
        }
    </script>

    <!-- 自定义工具类 -->
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .card-shadow {
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
            }
            .device-card-hover {
                transition: all 0.3s ease;
            }
            .device-card-hover:hover {
                transform: translateY(-4px);
                box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
            }
            .status-indicator {
                width: 10px;
                height: 10px;
                border-radius: 50%;
                display: inline-block;
            }
            .animate-fadeIn {
                animation: fadeIn 0.5s ease-in-out;
            }
            .toggle-switch {
                position: relative;
                display: inline-block;
                width: 50px;
                height: 24px;
            }
            .toggle-switch input {
                opacity: 0;
                width: 0;
                height: 0;
            }
            .toggle-slider {
                position: absolute;
                cursor: pointer;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background-color: #ccc;
                transition: .4s;
                border-radius: 24px;
            }
            .toggle-slider:before {
                position: absolute;
                content: "";
                height: 16px;
                width: 16px;
                left: 4px;
                bottom: 4px;
                background-color: white;
                transition: .4s;
                border-radius: 50%;
            }
            input:checked + .toggle-slider {
                background-color: #165DFF;
            }
            input:checked + .toggle-slider:before {
                transform: translateX(26px);
            }
            /* 进度条样式 */
            .percent-slider {
                -webkit-appearance: none;
                width: 100%;
                height: 6px;
                border-radius: 3px;
                background: #ddd;
                outline: none;
            }
            .percent-slider::-webkit-slider-thumb {
                -webkit-appearance: none;
                appearance: none;
                width: 18px;
                height: 18px;
                border-radius: 50%;
                background: #165DFF;
                cursor: pointer;
                transition: all 0.15s ease;
            }
            .percent-slider::-webkit-slider-thumb:hover {
                transform: scale(1.2);
                box-shadow: 0 0 5px rgba(22, 93, 255, 0.5);
            }
            @keyframes fadeIn {
                from { opacity: 0; }
                to { opacity: 1; }
            }
        }
    </style>
</head>

<body class="bg-gray-50 min-h-screen font-sans">
    <!-- 主控制页面 -->
    <div id="control-page">
        <!-- 顶部导航栏 -->
        <header class="bg-white shadow-sm fixed top-0 left-0 right-0 z-30">
            <div class="container mx-auto px-4 py-3 flex justify-between items-center">
                <div class="flex items-center">
                    <i class="fa fa-cogs text-primary text-xl mr-2"></i>
                    <h1 class="text-lg font-bold text-gray-800">物联网设备控制中心</h1>
                </div>

                <div class="flex items-center space-x-6">
                    <div class="hidden md:flex items-center text-sm text-gray-600">
                        <i class="fa fa-clock-o mr-1"></i>
                        <span id="current-time">--:--:--</span>
                    </div>

                    <div class="flex items-center">
                        <span id="user-info" class="hidden md:inline-block mr-2 text-sm font-medium">
                            <i class="fa fa-user-circle mr-1"></i>
                            <span id="current-username">管理员</span>
                        </span>
                        <button id="logout-btn" class="text-gray-500 hover:text-danger transition-colors duration-300">
                            <i class="fa fa-sign-out"></i>
                            <span class="hidden md:inline-block ml-1">退出</span>
                        </button>
                    </div>
                </div>
            </div>
        </header>

        <!-- 系统状态概览 -->
        <div class="bg-primary text-white py-2 mt-16">
            <div class="container mx-auto px-4">
                <div class="flex flex-wrap items-center justify-between">
                    <div class="flex items-center mb-2 md:mb-0">
                        <i class="fa fa-server mr-2"></i>
                        <span>系统状态: </span>
                        <span id="system-status-indicator"
                            class="ml-2 px-2 py-0.5 bg-success/20 text-success text-xs rounded-full flex items-center">
                            <span class="w-1.5 h-1.5 bg-success rounded-full mr-1 animate-pulse"></span>
                            正常运行中
                        </span>
                    </div>
                    <div class="text-xs text-white/80">
                        协议版本: v1.0 | MQTT服务器: <span id="mqtt-server-status">未连接</span> | 数据更新间隔: 3秒
                    </div>
                </div>
            </div>
        </div>

        <!-- 主内容区 -->
        <main class="container mx-auto px-4 py-6">
            <!-- 快速状态卡片 -->
            <section class="my-6 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
                <div class="bg-white rounded-xl p-4 shadow-sm device-card-hover">
                    <div class="flex justify-between items-start">
                        <div>
                            <p class="text-gray-500 text-sm">在线设备</p>
                            <p class="text-2xl font-bold mt-1 text-success" id="online-devices">0</p>
                            <p class="text-xs text-gray-500 mt-1">共<span id="total-devices">0</span>台设备</p>
                        </div>
                        <div class="w-10 h-10 rounded-full bg-success/10 flex items-center justify-center text-success">
                            <i class="fa fa-plug"></i>
                        </div>
                    </div>
                </div>

                <div class="bg-white rounded-xl p-4 shadow-sm device-card-hover">
                    <div class="flex justify-between items-start">
                        <div>
                            <p class="text-gray-500 text-sm">当前温度</p>
                            <p class="text-2xl font-bold mt-1 text-primary" id="current-temp">--.-°C</p>
                            <p class="text-xs text-gray-500 mt-1">来自温度传感器</p>
                        </div>
                        <div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary">
                            <i class="fa fa-thermometer-half"></i>
                        </div>
                    </div>
                </div>

                <div class="bg-white rounded-xl p-4 shadow-sm device-card-hover">
                    <div class="flex justify-between items-start">
                        <div>
                            <p class="text-gray-500 text-sm">当前湿度</p>
                            <p class="text-2xl font-bold mt-1 text-secondary" id="current-humidity">--%</p>
                            <p class="text-xs text-gray-500 mt-1">来自湿度传感器</p>
                        </div>
                        <div
                            class="w-10 h-10 rounded-full bg-secondary/10 flex items-center justify-center text-secondary">
                            <i class="fa fa-tint"></i>
                        </div>
                    </div>
                </div>

                <div class="bg-white rounded-xl p-4 shadow-sm device-card-hover">
                    <div class="flex justify-between items-start">
                        <div>
                            <p class="text-gray-500 text-sm">警报状态</p>
                            <p class="text-2xl font-bold mt-1 text-success" id="alarm-status">正常</p>
                            <p class="text-xs text-gray-500 mt-1">无异常情况</p>
                        </div>
                        <div class="w-10 h-10 rounded-full bg-success/10 flex items-center justify-center text-success">
                            <i class="fa fa-bell-o"></i>
                        </div>
                    </div>
                </div>
            </section>

            <!-- 温湿度趋势图和监控画面 -->
            <section class="my-6 grid grid-cols-1 lg:grid-cols-2 gap-6">
                <div class="bg-white rounded-xl p-5 shadow-sm">
                    <div class="flex justify-between items-center mb-4">
                        <h2 class="text-lg font-bold text-gray-800">温湿度趋势图</h2>
                        <div class="flex space-x-2">
                            <button class="time-filter px-3 py-1 text-xs bg-primary text-white rounded-full"
                                data-range="hour">1小时</button>
                            <button
                                class="time-filter px-3 py-1 text-xs bg-gray-100 hover:bg-gray-200 rounded-full transition-all duration-300"
                                data-range="day">24小时</button>
                            <button
                                class="time-filter px-3 py-1 text-xs bg-gray-100 hover:bg-gray-200 rounded-full transition-all duration-300"
                                data-range="week">7天</button>
                        </div>
                    </div>
                    <div id="temp-humidity-chart" class="w-full h-[300px]"></div>
                </div>

                <!-- 监控画面 (集成mjpg-streamer) -->
                <div class="bg-white rounded-xl p-5 shadow-sm">
                    <div class="flex justify-between items-center mb-4">
                        <h2 class="text-lg font-bold text-gray-800">实时监控</h2>
                        <div class="flex items-center space-x-3">
                            <span class="text-xs text-gray-500 flex items-center">
                                <span class="status-indicator bg-success mr-1"></span>
                                <span id="monitor-status">连接中...</span>
                            </span>
                            <button id="refresh-monitor" class="text-primary text-sm flex items-center hover:underline">
                                <i class="fa fa-refresh mr-1"></i>
                                <span>刷新</span>
                            </button>
                        </div>
                    </div>
                    <div class="relative bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
                        <!-- 集成mjpg-streamer的监控画面 -->
                        <iframe id="monitor-iframe" src="http://192.168.0.157:8080/stream_simple.html" title="实时监控画面"
                            class="w-full h-[300px] border-0" onload="monitorLoaded()"
                            onerror="monitorError()"></iframe>

                        <!-- 加载状态遮罩 -->
                        <div id="monitor-loading"
                            class="absolute inset-0 bg-gray-200/80 flex items-center justify-center">
                            <div class="text-center">
                                <i class="fa fa-circle-o-notch fa-spin text-2xl text-gray-600 mb-2"></i>
                                <p class="text-sm text-gray-600">监控画面加载中...</p>
                            </div>
                        </div>

                        <div class="absolute bottom-2 left-2 bg-black/50 text-white text-xs px-2 py-1 rounded">
                            <i class="fa fa-clock-o mr-1"></i>
                            <span id="monitor-timestamp">--:--:--</span>
                        </div>
                    </div>

                    <!-- 监控设备切换 -->
                    <div class="grid grid-cols-3 gap-2 mt-3 text-xs">
                        <button class="monitor-camera-btn bg-primary text-white p-2 rounded" data-camera="1"
                            data-url="http://192.168.0.157:8080/stream_simple.html">
                            <p>摄像头1</p>
                            <p>仓库区域</p>
                        </button>
                        <button
                            class="monitor-camera-btn bg-gray-50 text-gray-800 p-2 rounded hover:bg-gray-100 transition-colors"
                            data-camera="2" data-url="http://192.168.0.120:8080/stream_simple.html">
                            <p>摄像头2</p>
                            <p>设备区域</p>
                        </button>
                        <button
                            class="monitor-camera-btn bg-gray-50 text-gray-800 p-2 rounded hover:bg-gray-100 transition-colors"
                            data-camera="3" data-url="http://对方设备IP:8080/stream_simple.html">
                            <p>摄像头3</p>
                            <p>入口区域</p>
                        </button>
                    </div>
                </div>
            </section>

            <!-- 设备控制选项卡 -->
            <section class="my-6">
                <div class="bg-white rounded-xl shadow-sm overflow-hidden">
                    <!-- 选项卡导航 -->
                    <div class="border-b border-gray-200">
                        <div class="flex overflow-x-auto">
                            <button
                                class="device-tab py-4 px-6 text-primary border-b-2 border-primary font-medium whitespace-nowrap"
                                data-tab="stm32">
                                STM32 设备
                            </button>
                            <button
                                class="device-tab py-4 px-6 text-gray-500 hover:text-gray-700 border-b-2 border-transparent whitespace-nowrap"
                                data-tab="modbus">
                                Modbus 设备
                            </button>
                            <button
                                class="device-tab py-4 px-6 text-gray-500 hover:text-gray-700 border-b-2 border-transparent whitespace-nowrap"
                                data-tab="metaServer">
                                元服务器设备
                            </button>
                        </div>
                    </div>

                    <!-- STM32设备控制区 -->
                    <div class="device-content p-5" id="stm32-content">
                        <h2 class="text-lg font-bold text-gray-800 mb-4">STM32 设备控制</h2>
                        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5" id="stm32-devices-container">
                            <!-- 设备将通过JavaScript动态生成 -->
                            <div class="text-center py-10 text-gray-500">
                                <i class="fa fa-circle-o-notch fa-spin text-2xl mb-2"></i>
                                <p>加载设备中...</p>
                            </div>
                        </div>
                    </div>

                    <!-- Modbus设备控制区 -->
                    <div class="device-content p-5 hidden" id="modbus-content">
                        <h2 class="text-lg font-bold text-gray-800 mb-4">Modbus 设备控制</h2>
                        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5" id="modbus-devices-container">
                            <!-- 设备将通过JavaScript动态生成 -->
                            <div class="text-center py-10 text-gray-500">
                                <i class="fa fa-circle-o-notch fa-spin text-2xl mb-2"></i>
                                <p>加载设备中...</p>
                            </div>
                        </div>
                    </div>

                    <!-- 元服务器设备控制区 -->
                    <div class="device-content p-5 hidden" id="metaServer-content">
                        <h2 class="text-lg font-bold text-gray-800 mb-4">元服务器设备控制</h2>
                        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5"
                            id="metaServer-devices-container">
                            <!-- 设备将通过JavaScript动态生成 -->
                            <div class="text-center py-10 text-gray-500">
                                <i class="fa fa-circle-o-notch fa-spin text-2xl mb-2"></i>
                                <p>加载设备中...</p>
                            </div>
                        </div>
                    </div>
                </div>
            </section>

            <!-- 操作日志 -->
            <section class="my-6">
                <div class="bg-white rounded-xl p-5 shadow-sm">
                    <h2 class="text-lg font-bold text-gray-800 mb-4">操作日志</h2>
                    <div class="overflow-x-auto max-h-[200px] overflow-y-auto pr-2" id="operation-log">
                        <div class="text-sm text-gray-500 mb-2">
                            <span class="text-gray-400">[--:--:--]</span> 系统初始化完成
                        </div>
                    </div>
                </div>
            </section>
        </main>

        <!-- 页脚 -->
        <footer class="bg-white border-t border-gray-200 py-4 mt-auto">
            <div class="container mx-auto px-4 text-center text-gray-500 text-sm">
                <p>物联网设备控制中心 &copy; 2025</p>
                <p class="mt-1">协议版本: v1.0 | 数据每3秒自动更新</p>
            </div>
        </footer>
    </div>

    <!-- 通知提示组件 -->
    <div id="notification"
        class="fixed top-4 right-4 bg-white shadow-lg rounded-lg p-4 transform translate-x-full transition-all duration-300 flex items-center max-w-xs z-50">
        <div id="notification-icon"
            class="w-8 h-8 rounded-full flex items-center justify-center mr-3 bg-success/10 text-success">
            <i class="fa fa-check"></i>
        </div>
        <div>
            <h4 id="notification-title" class="font-medium text-gray-800">操作成功</h4>
            <p id="notification-message" class="text-sm text-gray-500 mt-1">设备已成功开启</p>
        </div>
        <button id="close-notification" class="ml-4 text-gray-400 hover:text-gray-600">
            <i class="fa fa-times"></i>
        </button>
    </div>

    <script>
        // 全局变量
        let tempHumidityChart = null;
        let token = localStorage.getItem('iot_token');
        let deviceData = {
            stm32: {},
            modbus: {},
            metaServer: {}
        }; // 存储设备数据
        let updateInterval = null;
        const API_BASE_URL = ''; // 服务器API基础路径，与服务器保持一致

        // 设备名称与图标映射
        const deviceNameIcons = {
            '冷藏柜': 'fa-snowflake-o',
            '电源插座': 'fa-power-off',
            '门锁': 'fa-lock',
            '室内是否有人': 'fa-user',
            '排风扇': 'fa-fan',
            '灯光状态': 'fa-lightbulb-o',
            '温度传感器': 'fa-thermometer-half',
            '湿度传感器': 'fa-tint',
            '险情控制': 'fa-exclamation-triangle',
            '空调模式': 'fa-snowflake-o',
            '窗帘控制': 'fa-columns',
            '窗户控制': 'fa-window-maximize',
            '商超广告大屏': 'fa-television',
            '水产水量控制': 'fa-tint',
            '空调电源状态': 'fa-power-off',
            '人体红外检测': 'fa-user-secret',
            '烟感控制': 'fa-fire-extinguisher',
            '遮阳板控制': 'fa-umbrella',
            '通风设计': 'fa-wind',
            '灯光控制': 'fa-lightbulb-o',
            '收银台钱锁控制': 'fa-lock',
            '安检设备控制': 'fa-shield'
        };

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function () {
            // 检查登录状态
            const username = localStorage.getItem('usr_user_name');
            if (!username) {
                // 未登录，跳转到登录页
                window.location.href = '/login.html';
                return;
            }

            // 设置当前用户名
            document.getElementById('current-username').textContent = username;

            // 初始化页面
            initPage();

            // 登出按钮事件
            document.getElementById('logout-btn').addEventListener('click', handleLogout);

            // 关闭通知
            document.getElementById('close-notification').addEventListener('click', hideNotification);

            // 设备选项卡切换
            document.querySelectorAll('.device-tab').forEach(tab => {
                tab.addEventListener('click', function () {
                    // 切换选项卡样式
                    document.querySelectorAll('.device-tab').forEach(t => {
                        t.classList.remove('text-primary', 'border-primary');
                        t.classList.add('text-gray-500', 'border-transparent');
                    });
                    this.classList.remove('text-gray-500', 'border-transparent');
                    this.classList.add('text-primary', 'border-primary');

                    // 切换内容显示
                    const tabName = this.getAttribute('data-tab');
                    document.querySelectorAll('.device-content').forEach(content => {
                        content.classList.add('hidden');
                    });
                    document.getElementById(`${tabName}-content`).classList.remove('hidden');
                });
            });

            // 时间过滤器
            document.querySelectorAll('.time-filter').forEach(filter => {
                filter.addEventListener('click', function () {
                    document.querySelectorAll('.time-filter').forEach(f => {
                        f.classList.remove('bg-primary', 'text-white');
                        f.classList.add('bg-gray-100', 'hover:bg-gray-200');
                    });
                    this.classList.remove('bg-gray-100', 'hover:bg-gray-200');
                    this.classList.add('bg-primary', 'text-white');
                    updateChartData(this.getAttribute('data-range'));
                });
            });

            // 刷新监控画面
            document.getElementById('refresh-monitor').addEventListener('click', refreshMonitor);

            // 监控摄像头切换
            document.querySelectorAll('.monitor-camera-btn').forEach(btn => {
                btn.addEventListener('click', function () {
                    // 切换按钮样式
                    document.querySelectorAll('.monitor-camera-btn').forEach(b => {
                        b.classList.remove('bg-primary', 'text-white');
                        b.classList.add('bg-gray-50', 'text-gray-800');
                    });
                    this.classList.remove('bg-gray-50', 'text-gray-800');
                    this.classList.add('bg-primary', 'text-white');

                    // 切换摄像头
                    const cameraUrl = this.getAttribute('data-url');
                    switchCamera(cameraUrl);
                });
            });
        });

        // 初始化页面
        function initPage() {
            initTimeDisplay();
            initChart();
            logOperation('用户进入控制中心');

            // 立即获取一次数据
            fetchDeviceData();

            // 启动定时更新
            startDataUpdate();
        }

        // 处理登出
        function handleLogout() {
            // 清除本地存储
            localStorage.removeItem('usr_user_name');
            localStorage.removeItem('iot_token');

            // 清除定时更新
            if (updateInterval) {
                clearInterval(updateInterval);
                updateInterval = null;
            }

            // 跳转到登录页
            window.location.href = '/login.html';
            logOperation('用户退出系统');
        }

        // 初始化时间显示
        function initTimeDisplay() {
            function updateTime() {
                const now = new Date();
                const timeStr = now.toTimeString().slice(0, 8);
                document.getElementById('current-time').textContent = timeStr;
                document.getElementById('monitor-timestamp').textContent = timeStr;
            }

            // 初始更新
            updateTime();
            // 每秒更新
            setInterval(updateTime, 1000);
        }

        // 初始化图表
        function initChart() {
            const chartDom = document.getElementById('temp-humidity-chart');
            tempHumidityChart = echarts.init(chartDom);

            // 初始数据
            const initialData = generateTimeSeriesData(60); // 1小时数据，每分钟一个点

            const option = {
                tooltip: {
                    trigger: 'axis',
                    axisPointer: {
                        type: 'cross'
                    }
                },
                legend: {
                    data: ['温度(°C)', '湿度(%)'],
                    top: 0
                },
                grid: {
                    left: '3%',
                    right: '4%',
                    bottom: '3%',
                    containLabel: true
                },
                xAxis: {
                    type: 'category',
                    boundaryGap: false,
                    data: initialData.times
                },
                yAxis: [
                    {
                        type: 'value',
                        name: '温度(°C)',
                        min: 15,
                        max: 35,
                        position: 'left',
                        axisLine: {
                            lineStyle: {
                                color: '#165DFF'
                            }
                        }
                    },
                    {
                        type: 'value',
                        name: '湿度(%)',
                        min: 30,
                        max: 80,
                        position: 'right',
                        axisLine: {
                            lineStyle: {
                                color: '#36CFC9'
                            }
                        }
                    }
                ],
                series: [
                    {
                        name: '温度(°C)',
                        type: 'line',
                        data: initialData.temps,
                        symbol: 'none',
                        lineStyle: {
                            width: 2,
                            color: '#165DFF'
                        },
                        areaStyle: {
                            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                                { offset: 0, color: 'rgba(22, 93, 255, 0.2)' },
                                { offset: 1, color: 'rgba(22, 93, 255, 0)' }
                            ])
                        }
                    },
                    {
                        name: '湿度(%)',
                        type: 'line',
                        yAxisIndex: 1,
                        data: initialData.humis,
                        symbol: 'none',
                        lineStyle: {
                            width: 2,
                            color: '#36CFC9'
                        },
                        areaStyle: {
                            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                                { offset: 0, color: 'rgba(54, 207, 201, 0.2)' },
                                { offset: 1, color: 'rgba(54, 207, 201, 0)' }
                            ])
                        }
                    }
                ]
            };

            tempHumidityChart.setOption(option);

            // 响应窗口大小变化
            window.addEventListener('resize', () => {
                tempHumidityChart.resize();
            });
        }

        // 生成时间序列数据
        function generateTimeSeriesData(points) {
            const times = [];
            const temps = [];
            const humis = [];

            const now = new Date();

            for (let i = points - 1; i >= 0; i--) {
                const time = new Date(now - i * 60 * 1000); // 每分钟一个点
                const hour = time.getHours().toString().padStart(2, '0');
                const minute = time.getMinutes().toString().padStart(2, '0');
                times.push(`${hour}:${minute}`);

                // 生成有波动的温度数据 (23-27°C)
                const baseTemp = 25;
                temps.push((baseTemp + (Math.random() * 4 - 2)).toFixed(1));

                // 生成有波动的湿度数据 (40-60%)
                const baseHumi = 50;
                humis.push((baseHumi + (Math.random() * 20 - 10)).toFixed(0));
            }

            return { times, temps, humis };
        }

        // 更新图表数据
        function updateChartData(range) {
            let points = 60; // 默认1小时数据

            if (range === 'day') {
                points = 24; // 24小时，每小时一个点
            } else if (range === 'week') {
                points = 7; // 7天，每天一个点
            }

            const newData = generateTimeSeriesData(points);

            tempHumidityChart.setOption({
                xAxis: {
                    data: newData.times
                },
                series: [
                    {
                        data: newData.temps
                    },
                    {
                        data: newData.humis
                    }
                ]
            });
        }

        // 开始定时更新数据
        function startDataUpdate() {
            // 清除已有的定时器
            if (updateInterval) {
                clearInterval(updateInterval);
            }

            // 每3秒更新一次数据（与服务器配置一致）
            updateInterval = setInterval(() => {
                fetchDeviceData();
            }, 3000);
        }

        // 从服务器获取设备数据（关键：与服务器共享内存交互）
        function fetchDeviceData() {
            fetch(`${API_BASE_URL}?action=get_shmem_data`, {
                method: 'GET',
                credentials: 'include',
                headers: {
                    'Accept': 'application/json'
                }
            })
                .then(response => {
                    // 检查HTTP响应状态
                    if (!response.ok) {
                        throw new Error(`HTTP错误: ${response.status}`);
                    }
                    return response.json();
                })
                .then(data => {
                    // 检查是否有错误
                    if (data.error) {
                        throw new Error(data.error);
                    }

                    // 更新系统状态
                    updateSystemStatus(true);

                    // 存储设备数据（与服务器数据结构匹配）
                    if (data.stm32 && data.stm32.data) {
                        deviceData.stm32 = data.stm32.data.reduce((obj, item) => {
                            obj[item.key] = item;
                            return obj;
                        }, {});
                    }

                    if (data.modbus && data.modbus.data) {
                        deviceData.modbus = data.modbus.data.reduce((obj, item) => {
                            obj[item.key] = item;
                            return obj;
                        }, {});
                    }

                    if (data.metaServer && data.metaServer.data) {
                        deviceData.metaServer = data.metaServer.data.reduce((obj, item) => {
                            obj[item.key] = item;
                            return obj;
                        }, {});
                    }

                    // 更新设备显示
                    renderDevices('stm32');
                    renderDevices('modbus');
                    renderDevices('metaServer');

                    // 更新快速状态卡片
                    updateStatusCards();

                    // 更新图表
                    updateChartWithNewData();

                    logOperation('设备数据更新成功');
                })
                .catch(error => {
                    updateSystemStatus(false);
                    const errorMsg = `获取数据失败: ${error.message}`;
                    logOperation(errorMsg);
                    showNotification('数据更新失败', errorMsg, 'error');
                    console.error('获取设备数据错误:', error);
                });
        }

        // 更新系统状态显示
        function updateSystemStatus(connected) {
            const indicator = document.getElementById('system-status-indicator');
            const mqttStatus = document.getElementById('mqtt-server-status');

            if (connected) {
                indicator.className = 'ml-2 px-2 py-0.5 bg-success/20 text-success text-xs rounded-full flex items-center';
                indicator.innerHTML = '<span class="w-1.5 h-1.5 bg-success rounded-full mr-1 animate-pulse"></span>正常运行中';
                mqttStatus.textContent = '已连接';
            } else {
                indicator.className = 'ml-2 px-2 py-0.5 bg-danger/20 text-danger text-xs rounded-full flex items-center';
                indicator.innerHTML = '<span class="w-1.5 h-1.5 bg-danger rounded-full mr-1 animate-pulse"></span>连接异常';
                mqttStatus.textContent = '连接失败';
            }
        }

        // 更新状态卡片
        function updateStatusCards() {
            // 计算在线设备数量
            const stm32Count = Object.keys(deviceData.stm32).length;
            const modbusCount = Object.keys(deviceData.modbus).length;
            const metaServerCount = Object.keys(deviceData.metaServer).length;
            const totalCount = stm32Count + modbusCount + metaServerCount;

            // 更新在线设备数量
            document.getElementById('online-devices').textContent = totalCount;
            document.getElementById('total-devices').textContent = totalCount;

            // 更新温度和湿度
            const tempSensor = findDeviceByTypeAndName('stm32', '温度传感器');
            const humiSensor = findDeviceByTypeAndName('stm32', '湿度传感器');

            if (tempSensor) {
                const tempValue = tempSensor.type === 3 ? tempSensor.floatValue : tempSensor.value;
                document.getElementById('current-temp').textContent = `${tempValue.toFixed(1)}°C`;
            }

            if (humiSensor) {
                const humiValue = humiSensor.type === 3 ? humiSensor.floatValue : humiSensor.value;
                document.getElementById('current-humidity').textContent = `${humiValue.toFixed(0)}%`;
            }

            // 更新警报状态
            const alarmDevice = findDeviceByTypeAndName('stm32', '险情控制');
            if (alarmDevice) {
                const alarmStatus = alarmDevice.value === 0 ? '正常' : '警报中';
                const alarmEl = document.getElementById('alarm-status');
                alarmEl.textContent = alarmStatus;

                if (alarmStatus === '警报中') {
                    alarmEl.className = 'text-2xl font-bold mt-1 text-danger';
                    showNotification('警报提醒', '检测到异常情况，请注意', 'warning');
                } else {
                    alarmEl.className = 'text-2xl font-bold mt-1 text-success';
                }
            }
        }

        // 根据类型和名称查找设备
        function findDeviceByTypeAndName(type, name) {
            const devices = deviceData[type] || {};
            return Object.values(devices).find(device => device.name === name);
        }

        // 判断设备是否需要使用进度条控制
        function usePercentControl(deviceType, deviceName) {
            // Modbus设备中需要百分比控制的设备
            if (deviceType === 'modbus') {
                return ['窗帘控制', '水产水量控制'].includes(deviceName);
            }

            // metaServer设备中需要百分比控制的设备
            if (deviceType === 'metaServer') {
                return ['遮阳板控制', '灯光控制'].includes(deviceName);
            }

            return false;
        }

        // 判断设备是否是空调模式控制
        function isAirConditionerMode(deviceType, deviceName) {
            return deviceType === 'modbus' && deviceName === '空调模式';
        }

        // 判断设备是否是只读设备
        function isReadOnlyDevice(deviceType, deviceName) {
            // metaServer中的只读设备
            if (deviceType === 'metaServer') {
                return ['人体红外检测', '烟感控制'].includes(deviceName);
            }

            // 温湿度传感器是只读设备
            return deviceName === '温度传感器' || deviceName === '湿度传感器';
        }

        // 获取空调模式文本
        function getAirConditionerModeText(value) {
            switch (parseInt(value)) {
                case 11: return '制冷';
                case 22: return '制热';
                case 33: return '除湿';
                default: return '未知';
            }
        }

        // 渲染设备列表（核心：修改为目标样式）
        function renderDevices(deviceType) {
            const container = document.getElementById(`${deviceType}-devices-container`);
            if (!container) return;

            const devices = Object.values(deviceData[deviceType] || {});

            // 清空容器
            container.innerHTML = '';

            if (devices.length === 0) {
                container.innerHTML = `
                    <div class="text-center py-10 text-gray-500">
                        <i class="fa fa-info-circle text-xl mb-2"></i>
                        <p>未找到${getDeviceTypeName(deviceType)}设备</p>
                    </div>
                `;
                return;
            }

            // 为每个设备创建卡片（目标样式：横向布局，左侧信息，右侧控制）
            devices.forEach(device => {
                const isReadOnly = isReadOnlyDevice(deviceType, device.name);
                const usePercent = usePercentControl(deviceType, device.name);
                const isAirMode = isAirConditionerMode(deviceType, device.name);

                // 获取设备图标
                const icon = deviceNameIcons[device.name] || 'fa-cog';

                // 确定显示值
                let displayValue = '';
                if (device.name === '温度传感器' || device.name === '湿度传感器') {
                    // 温湿度传感器显示floatvalue
                    displayValue = device.floatValue.toFixed(device.name === '温度传感器' ? 1 : 0);
                } else if (isAirMode) {
                    // 空调模式显示文本
                    displayValue = getAirConditionerModeText(device.value);
                } else if (usePercent) {
                    // 百分比控制设备显示百分比
                    displayValue = `${device.value}%`;
                } else if (device.type === 1 ||
                    (device.type === 2 &&
                        (device.name.includes('电源') || device.name.includes('开关') ||
                            device.name.includes('锁') || device.name.includes('灯') ||
                            device.name.includes('窗') || device.name.includes('大屏') ||
                            device.name.includes('扇') || device.name.includes('险情')))) {
                    // 开关类型设备显示开/关
                    displayValue = device.value === 1 ? '开' : '关';
                } else {
                    // 其他设备直接显示值
                    displayValue = device.value;
                }

                // 添加单位
                const unit = getUnitByDeviceName(device.name);
                if (unit && !usePercent && !['温度传感器', '湿度传感器'].includes(device.name)) {
                    displayValue += unit;
                }

                // 创建设备卡片（目标样式：横向布局，左侧信息，右侧控制）
                const card = document.createElement('div');
                card.className = 'bg-white rounded-xl p-5 shadow-sm device-card-hover flex flex-col md:flex-row justify-between items-center';
                card.innerHTML = `
                    <!-- 左侧：设备信息 -->
                    <div class="flex items-center mb-4 md:mb-0 w-full md:w-auto">
                        <div class="w-12 h-12 rounded-full ${getIconBgColor(device.name)} flex items-center justify-center mr-4">
                            <i class="fa ${icon} ${getIconColor(device.name)} text-xl"></i>
                        </div>
                        <div>
                            <h3 class="font-bold text-gray-800 text-lg">${device.name}</h3>
                            <div class="flex items-center mt-1">
                                <span class="status-indicator ${getDeviceStatusColor(device, displayValue)} mr-2"></span>
                                <p class="text-sm text-gray-600">状态: <span class="${getValueColorClass(device, displayValue, deviceType)} font-medium">${displayValue}</span></p>
                            </div>
                            ${device.addr ? `<p class="text-xs text-gray-500 mt-1">地址: ${device.addr}</p>` : ''}
                        </div>
                    </div>
                    
                    <!-- 右侧：控制组件 -->
                    <div class="w-full md:w-auto flex flex-col items-end">
                        ${isReadOnly ? `
                            <p class="text-sm text-gray-600 py-2">${displayValue}</p>
                        ` : usePercent ? `
                            <div class="w-full md:w-48">
                                <div class="flex justify-between items-center mb-1">
                                    <span class="text-xs text-gray-500">0%</span>
                                    <span class="text-xs font-medium" id="percent-value-${deviceType}-${device.key}">${device.value}%</span>
                                    <span class="text-xs text-gray-500">100%</span>
                                </div>
                                <input type="range" min="0" max="100" value="${device.value}" 
                                       class="percent-slider" 
                                       data-device-type="${deviceType}" 
                                       data-key="${device.key}"
                                       id="slider-${deviceType}-${device.key}">
                            </div>
                            <p class="text-xs text-gray-500 mt-2">拖动滑块调整</p>
                        ` : isAirMode ? `
                            <select class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary focus:border-primary p-2"
                                    data-device-type="${deviceType}" 
                                    data-key="${device.key}">
                                <option value="11" ${device.value == 11 ? 'selected' : ''}>制冷</option>
                                <option value="22" ${device.value == 22 ? 'selected' : ''}>制热</option>
                                <option value="33" ${device.value == 33 ? 'selected' : ''}>除湿</option>
                            </select>
                            <p class="text-xs text-gray-500 mt-2">选择空调模式</p>
                        ` : `
                            <label class="toggle-switch">
                                <input type="checkbox" class="control-toggle" 
                                       data-device-type="${deviceType}" 
                                       data-key="${device.key}" 
                                       data-current-value="${device.value}"
                                       ${device.value === 1 ? 'checked' : ''}>
                                <span class="toggle-slider"></span>
                            </label>
                            <p class="text-xs text-gray-500 mt-2">点击切换状态</p>
                        `}
                    </div>
                `;

                container.appendChild(card);
            });

            // 为新添加的控制组件绑定事件
            // 1. 滑动开关事件
            container.querySelectorAll('.control-toggle').forEach(toggle => {
                toggle.addEventListener('change', handleDeviceControl);
            });

            // 2. 进度条事件
            container.querySelectorAll('.percent-slider').forEach(slider => {
                // 实时显示进度值
                slider.addEventListener('input', function () {
                    const deviceType = this.getAttribute('data-device-type');
                    const key = this.getAttribute('data-key');
                    const valueDisplay = document.getElementById(`percent-value-${deviceType}-${key}`);
                    if (valueDisplay) {
                        valueDisplay.textContent = `${this.value}%`;
                    }
                });

                // 进度条停止拖动后发送命令
                slider.addEventListener('change', handleDeviceControl);
            });

            // 3. 空调模式选择事件
            container.querySelectorAll('select').forEach(select => {
                select.addEventListener('change', handleDeviceControl);
            });
        }

        // 获取设备类型名称
        function getDeviceTypeName(type) {
            const names = {
                stm32: 'STM32',
                modbus: 'Modbus',
                metaServer: '元服务器'
            };
            return names[type] || type;
        }

        // 根据设备名称获取图标背景颜色
        function getIconBgColor(deviceName) {
            if (deviceName.includes('温度')) return 'bg-primary/10';
            if (deviceName.includes('湿度') || deviceName.includes('水')) return 'bg-secondary/10';
            if (deviceName.includes('电源') || deviceName.includes('灯光')) return 'bg-warning/10';
            if (deviceName.includes('锁') || deviceName.includes('险情') || deviceName.includes('安检')) return 'bg-danger/10';
            return 'bg-primary/10';
        }

        // 根据设备名称获取图标颜色
        function getIconColor(deviceName) {
            if (deviceName.includes('温度')) return 'text-primary';
            if (deviceName.includes('湿度') || deviceName.includes('水')) return 'text-secondary';
            if (deviceName.includes('电源') || deviceName.includes('灯光')) return 'text-warning';
            if (deviceName.includes('锁') || deviceName.includes('险情') || deviceName.includes('安检')) return 'text-danger';
            return 'text-primary';
        }

        // 获取设备状态指示灯颜色
        function getDeviceStatusColor(device, displayValue) {
            // 开关类型设备
            if (displayValue === '开') return 'bg-success';
            if (displayValue === '关') return 'bg-gray-300';

            // 警报状态
            if (device.name.includes('险情') && displayValue === '警报中') return 'bg-danger';

            // 默认状态
            return 'bg-primary';
        }

        // 根据设备值获取颜色样式
        function getValueColorClass(device, value, deviceType) {
            // 开关类型设备
            if (value === '开') return 'text-success';
            if (value === '关') return 'text-gray-500';

            // 空调模式
            if (isAirConditionerMode(deviceType, device.name)) {
                if (value === '制冷') return 'text-primary';
                if (value === '制热') return 'text-danger';
                if (value === '除湿') return 'text-secondary';
            }

            // 温度传感器特殊处理
            if (device.name.includes('温度')) {
                const temp = parseFloat(value);
                if (temp > 30) return 'text-danger';
                if (temp < 10) return 'text-blue-500';
                return 'text-success';
            }

            // 警报设备
            if (device.name.includes('险情') && value === '警报中') {
                return 'text-danger';
            }

            return 'text-gray-800';
        }

        // 根据设备名称获取单位
        function getUnitByDeviceName(name) {
            if (name.includes('温度')) return ' °C';
            if (name.includes('湿度') && !name.includes('传感器')) return ' %';
            if (name.includes('电压')) return ' V';
            if (name.includes('电流')) return ' A';
            return '';
        }

        // 处理设备控制（适配新的控制组件）
        function handleDeviceControl(e) {
            const deviceType = e.target.getAttribute('data-device-type');
            const key = parseInt(e.target.getAttribute('data-key'));

            // 获取设备信息
            const device = deviceData[deviceType][key];
            if (!device) {
                showNotification('操作失败', '未找到设备信息', 'error');
                return;
            }

            let newValue;
            if (e.target.type === 'checkbox') {
                // 滑动开关：直接取checked状态
                newValue = e.target.checked ? 1 : 0;
            } else if (e.target.type === 'range') {
                // 进度条：获取值
                newValue = parseInt(e.target.value);
            } else if (e.target.tagName === 'SELECT') {
                // 下拉选择框：空调模式
                newValue = parseInt(e.target.value);
            }

            // 发送控制命令到服务器
            sendControlCommand(deviceType, key, newValue, device.name);
        }

        // 发送控制命令到服务器（与服务器消息队列交互）
        function sendControlCommand(deviceType, key, value, deviceName) {
            // 构建控制命令JSON（与服务器消息格式匹配）
            const command = {};
            command[deviceType] = {
                data: [
                    {
                        key: key,
                        type: 2,
                        value: value
                    }
                ]
            };

            // 显示加载状态
            let statusText = '';
            if (usePercentControl(deviceType, deviceName)) {
                statusText = `${value}%`;
            } else if (isAirConditionerMode(deviceType, deviceName)) {
                statusText = getAirConditionerModeText(value);
            } else {
                statusText = value === 1 ? '开' : '关';
            }

            showNotification('处理中', `正在设置${deviceName}为${statusText}`, 'info');

            // 发送POST请求
            fetch(`${API_BASE_URL}?action=control_device`, {
                method: 'POST',
                credentials: 'include',
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                },
                body: JSON.stringify(command)
            })
                .then(response => {
                    if (!response.ok) {
                        throw new Error(`HTTP错误: ${response.status}`);
                    }
                    return response.json();
                })
                .then(data => {
                    if (data.status === 0 || data.error === undefined) {
                        showNotification('操作成功', `${deviceName}已设置为${statusText}`, 'success');
                        logOperation(`设备[${key}:${deviceName}]已设置为 ${value}(${statusText})`);

                        // 发送到消息队列的日志
                        logOperation(`已向消息队列发送控制指令: ${JSON.stringify(command)}`);

                        // 立即刷新数据
                        fetchDeviceData();
                    } else {
                        showNotification('操作失败', `${data.msg || '未知错误'}`, 'error');
                        logOperation(`控制设备[${key}:${deviceName}]失败: ${data.msg || '未知错误'}`);
                    }
                })
                .catch(error => {
                    showNotification('操作失败', `发送命令失败: ${error.message}`, 'error');
                    logOperation(`控制设备[${key}:${deviceName}]出错: ${error.message}`);
                    console.error('发送控制命令错误:', error);
                });
        }

        // 更新图表数据
        function updateChartWithNewData() {
            if (!tempHumidityChart) return;

            // 获取温度和湿度传感器数据
            const tempSensor = findDeviceByTypeAndName('stm32', '温度传感器');
            const humiSensor = findDeviceByTypeAndName('stm32', '湿度传感器');

            if (!tempSensor || !humiSensor) return;

            const option = tempHumidityChart.getOption();
            const now = new Date();
            const hour = now.getHours().toString().padStart(2, '0');
            const minute = now.getMinutes().toString().padStart(2, '0');
            const currentTime = `${hour}:${minute}`;

            // 获取最后一个时间点
            const lastTime = option.xAxis[0].data[option.xAxis[0].data.length - 1];

            // 如果时间变了才添加新数据点
            if (lastTime !== currentTime) {
                // 添加新数据点
                option.xAxis[0].data.push(currentTime);

                const tempValue = tempSensor.floatValue;
                option.series[0].data.push(tempValue.toFixed(1));

                const humiValue = humiSensor.floatValue;
                option.series[1].data.push(humiValue.toFixed(0));

                // 保持数据点数量不变，移除第一个点
                if (option.xAxis[0].data.length > 60) {
                    option.xAxis[0].data.shift();
                    option.series[0].data.shift();
                    option.series[1].data.shift();
                }

                tempHumidityChart.setOption(option);
            }
        }

        // 监控画面加载成功
        function monitorLoaded() {
            document.getElementById('monitor-loading').classList.add('hidden');
            document.getElementById('monitor-status').textContent = '实时监控';
            document.getElementById('monitor-status').parentElement.querySelector('.status-indicator').className = 'status-indicator bg-success mr-1';
        }

        // 监控画面加载失败
        function monitorError() {
            document.getElementById('monitor-loading').innerHTML = `
                <div class="text-center">
                    <i class="fa fa-exclamation-circle text-2xl text-danger mb-2"></i>
                    <p class="text-sm text-danger">监控画面加载失败</p>
                    <p class="text-xs text-gray-600 mt-1">请检查设备连接或点击刷新</p>
                </div>
            `;
            document.getElementById('monitor-status').textContent = '连接失败';
            document.getElementById('monitor-status').parentElement.querySelector('.status-indicator').className = 'status-indicator bg-danger mr-1';
        }

        // 刷新监控画面
        function refreshMonitor() {
            const iframe = document.getElementById('monitor-iframe');
            const currentSrc = iframe.src;

            // 显示加载状态
            document.getElementById('monitor-loading').classList.remove('hidden');
            document.getElementById('monitor-loading').innerHTML = `
                <div class="text-center">
                    <i class="fa fa-circle-o-notch fa-spin text-2xl text-gray-600 mb-2"></i>
                    <p class="text-sm text-gray-600">监控画面刷新中...</p>
                </div>
            `;

            // 重新加载iframe
            iframe.src = '';
            setTimeout(() => {
                iframe.src = currentSrc;
            }, 300);

            logOperation('监控画面已刷新');
        }

        // 切换摄像头
        function switchCamera(url) {
            const iframe = document.getElementById('monitor-iframe');

            // 显示加载状态
            document.getElementById('monitor-loading').classList.remove('hidden');
            document.getElementById('monitor-loading').innerHTML = `
                <div class="text-center">
                    <i class="fa fa-circle-o-notch fa-spin text-2xl text-gray-600 mb-2"></i>
                    <p class="text-sm text-gray-600">切换摄像头中...</p>
                </div>
            `;

            // 加载新的摄像头地址
            iframe.src = url;

            logOperation(`切换到新摄像头: ${url}`);
        }

        // 显示通知
        function showNotification(title, message, type = 'success') {
            const notification = document.getElementById('notification');
            const icon = document.getElementById('notification-icon');
            const titleEl = document.getElementById('notification-title');
            const messageEl = document.getElementById('notification-message');

            // 设置通知类型
            if (type === 'success') {
                icon.className = 'w-8 h-8 rounded-full flex items-center justify-center mr-3 bg-success/10 text-success';
                icon.innerHTML = '<i class="fa fa-check"></i>';
            } else if (type === 'error') {
                icon.className = 'w-8 h-8 rounded-full flex items-center justify-center mr-3 bg-danger/10 text-danger';
                icon.innerHTML = '<i class="fa fa-times"></i>';
            } else if (type === 'warning') {
                icon.className = 'w-8 h-8 rounded-full flex items-center justify-center mr-3 bg-warning/10 text-warning';
                icon.innerHTML = '<i class="fa fa-exclamation"></i>';
            } else if (type === 'info') {
                icon.className = 'w-8 h-8 rounded-full flex items-center justify-center mr-3 bg-primary/10 text-primary';
                icon.innerHTML = '<i class="fa fa-info"></i>';
            }

            // 设置内容
            titleEl.textContent = title;
            messageEl.textContent = message;

            // 显示通知
            notification.classList.remove('translate-x-full');

            // 3秒后自动隐藏
            setTimeout(hideNotification, 3000);
        }

        // 隐藏通知
        function hideNotification() {
            const notification = document.getElementById('notification');
            notification.classList.add('translate-x-full');
        }

        // 记录操作日志
        function logOperation(message) {
            const logContainer = document.getElementById('operation-log');
            const now = new Date();
            const timeStr = now.toTimeString().slice(0, 8);

            // 创建日志项
            const logItem = document.createElement('div');
            logItem.className = 'text-sm text-gray-500 mb-2 animate-fadeIn';
            logItem.innerHTML = `<span class="text-gray-400">[${timeStr}]</span> ${message}`;

            // 添加到日志容器顶部
            logContainer.insertBefore(logItem, logContainer.firstChild);

            // 限制日志数量
            if (logContainer.children.length > 20) {
                logContainer.removeChild(logContainer.lastChild);
            }
        }

        // 页面卸载时清理
        window.addEventListener('beforeunload', function () {
            if (updateInterval) {
                clearInterval(updateInterval);
            }
        });
    </script>
</body>

</html>